using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using Eneta.Portal.Forum.Controls.Common;
using Eneta.Portal.Forum.Core.Domain.Collections;
using Eneta.Portal.Forum.Core.Domain.Entities;
using Eneta.Portal.Forum.Core.Service.Application;
using Eneta.Portal.Forum.Utility;

namespace Eneta.Portal.Forum.Controls.Base
{
    /// <summary>
    /// Super class from which all forum controls will derive from
    /// </summary>
    public class BaseForumControl : UserControl, INamingContainer
    {
        private readonly ForumTimer _forumTimer = new ForumTimer(true);
        //private SharePointToolBar _toolBar;

        protected int _categoryID;
        protected int _topicID;
        protected int _forumID;
        protected int _messageID;
        protected string _forumName = string.Empty;

        /// <summary>
        /// Initializes a new instance of the <see cref="BaseForumControl"/> class.
        /// </summary>
        public BaseForumControl()
        {
            MessageMode = PostMode.New;
            Load += BaseForumControlLoad;
            //PreRender += BaseForumControlPreRender;
        }

        /// <summary>
        /// Gets or sets the _parent link.
        /// </summary>
        /// <value>The _parent link.</value>
        public string ParentLink { get; set; }

        /// <summary>
        /// Gets or sets the message mode.
        /// </summary>
        /// <value>The message mode.</value>
        public PostMode MessageMode { get; set; }

        /// <summary>
        /// Gets a reference to the server control's _parent control in the page control hierarchy.
        /// </summary>
        /// <value></value>
        public EnetaForumWebPart WebPartParent { get; set; }


        /// <summary>
        /// Validates and integer. Used for getting values from QueryString.
        /// Will return 0 for invalid or null objects.
        /// </summary>
        /// <param name="obj">The o.</param>
        /// <returns></returns>
        public static int ValidInt(object obj)
        {
            try
            {
                if (obj == null)
                    return 0;
                return int.Parse(obj.ToString());
            }
            catch (Exception)
            {
                return 0;
            }
        }

        private void BuildQuoteLinkUI(Core.Domain.Entities.Forum forum, DomainObject post)
        {
            var canQuote = false;

            if (ForumApplication.Instance.CurrentUser == null)
                return;

            if (forum.HasAccess(ForumApplication.Instance.CurrentUser, Permission.Rights.Reply))
            {
                canQuote = true;
            }

            if (canQuote)
            {
                var quoteLink = ForumApplication.Instance.GetLink(
                    SharePointForumControls.UpdateMessage,
                    "message={0}&{1}={2}", post.Id, ForumConstants.Query_PostMethod, PostMode.Quote);
                Controls.Add(new LiteralControl(string.Format("<a href={0}>{1}</a>&nbsp;", 
                                                              quoteLink, Resources.UI.TextQuote)));
            }
        }

        private void BuildReplyLinkUI(Core.Domain.Entities.Forum forum, Message post)
        {
            if (ForumApplication.Instance.CurrentUser == null)
                return;

            if (forum.HasAccess(ForumApplication.Instance.CurrentUser, Permission.Rights.Reply))
            {
                string replyLink = ForumApplication.Instance.GetLink(
                    SharePointForumControls.UpdateMessage,
                    "topic={0}&{1}={2}&message={3}", post.TopicId, ForumConstants.Query_PostMethod, PostMode.Reply, post.Id);
                Controls.Add(new LiteralControl(
                                 String.Format("<a href=\"{0}\">{1}</a>&nbsp;|&nbsp;", replyLink, 
                                               Resources.UI.TextReply)));
            }
        }

        private void BuildEditLinkUi(Core.Domain.Entities.Forum forum, Message post)
        {
            if (ForumApplication.Instance.CurrentUser == null)
                return;

            var canEdit = false;

            if (ForumApplication.Instance.CurrentUser.IsAdmin)
            {
                canEdit = true;
            }
            else
            {
                if (forum.HasAccess(ForumApplication.Instance.CurrentUser, Permission.Rights.Edit)
                    && post.Author.Id == ForumApplication.Instance.CurrentUser.Id)
                    canEdit = true;
            }

            if (canEdit)
            {
                string editLink = ForumApplication.Instance.GetLink(
                    SharePointForumControls.UpdateMessage,
                    "message={0}&{1}={2}", post.Id, ForumConstants.Query_PostMethod, PostMode.Edit);
                Controls.Add(new LiteralControl(string.Format("<a href={0}>{1}</a>&nbsp;|&nbsp;", editLink,
                                                              Resources.UI.TextEdit)));
            }
        }

        private static string FillUserInfoBox(ForumUser user)
        {
            var sb = new StringBuilder();

            sb.AppendFormat("{0}: {1}<br>", Resources.UI.UserInfoBoxJoined, user.Joined.ToShortDateString());
            sb.AppendFormat("{0}: {1}<br>", Resources.UI.UserInfoBoxPosts, user.NumPosts);

            return sb.ToString();
        }

        [Conditional("DEBUG")]
        private static void DisplayDebugUserInformation(StringBuilder footer)
        {
            //footer.AppendFormat("<br><br>Debug Information<br>");

            //if(ForumApplication.Instance.AppPoolUser != null)
            //    footer.AppendFormat("AppPool user: {0} (ID={1} [From SPWeb object])<br>",
            //                        ForumApplication.Instance.AppPoolUser.LoginName,
            //                        ForumApplication.Instance.AppPoolUser.ID);
            //else 
            //    footer.Append("AppPool user: null<br/>");

            //if(ForumApplication.Instance.SpUser != null)
            //    footer.AppendFormat("SPWeb user: {0} (ID={1} [From ForumApp.SpUser object])<br>",
            //                        ForumApplication.Instance.SpUser.LoginName,
            //                        ForumApplication.Instance.SpUser.ID);
            //else
            //    footer.Append("SPWeb user: null<br/>");

            //if(ForumApplication.Instance.CurrentUser != null)
            //    footer.AppendFormat("Forum user= {0} (ID={1} [From spforums_users list])<br>",
            //                        ForumApplication.Instance.CurrentUser.Name,
            //                        ForumApplication.Instance.CurrentUser.Id);
            //else
            //    footer.Append("Forum user: null<br/>");

            //footer.AppendFormat("Base Path={0}", ForumApplication.Instance.BasePath);
            
        }

        /// <summary>
        /// Handles the PreRender event of the BaseForumControl control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        //private void BaseForumControlPreRender(object sender, EventArgs e)
        //{
        //    var userName = string.Empty;
        //    if (ForumApplication.Instance.SpUser != null)
        //        userName = ForumApplication.Instance.SpUser.Name;
        //    _toolBar = new SharePointToolBar(userName);

        //    _toolBar.AddItem(Resources.UI.ToolbarHome, ForumApplication.Instance.GetLink(SharePointForumControls.ViewForums));
        //    if(ForumApplication.Instance.SpUser != null)
        //        _toolBar.AddItem(Resources.UI.ToolbarMyProfile, ForumApplication.Instance.GetLink(SharePointForumControls.ViewProfile));
        //    _toolBar.AddItem(Resources.UI.ToolbarMembers, ForumApplication.Instance.GetLink(SharePointForumControls.ViewMembers));

        //    if(ForumApplication.Instance.CurrentUser != null)
        //        if (ForumApplication.Instance.CurrentUser.IsAdmin)
        //            _toolBar.AddItem(Resources.UI.ToolbarAdmin, ForumApplication.Instance.GetLink(SharePointForumControls.AdministrationPanel));
        //}

        /// <summary>
        /// Determines the post method.
        /// </summary>
        private void DeterminePostMethod()
        {
            var postMethod = HttpContext.Current.Request.QueryString[ForumConstants.Query_PostMethod];
            if (null != postMethod)
            {
                MessageMode = (PostMode)Enum.Parse(typeof (PostMode), postMethod);
            }
            else
            {
                MessageMode = PostMode.New;
            }
        }

        /// <summary>
        /// Assigns the ids from query strings.
        /// </summary>
        private void AssignIdsFromQueryStrings()
        {
            _messageID = ValidInt(HttpContext.Current.Request.QueryString["message"]);
            _topicID = ValidInt(HttpContext.Current.Request.QueryString["topic"]);
            _forumID = ValidInt(HttpContext.Current.Request.QueryString["forum"]);
            _categoryID = ValidInt(HttpContext.Current.Request.QueryString["category"]);

            // if there's a message id but no topic id, derive the topic from the message
            if ((_messageID != 0) && (_topicID == 0))
            {
                _topicID = RepositoryRegistry.MessageRepository.GetById(_messageID).TopicId;
            }

            // if there's a topic id but no forum id, derive the forum id from the topic
            if ((_topicID != 0) && (_forumID == 0))
            {
                _forumID = RepositoryRegistry.TopicRepository.GetById(_topicID).ForumId;
            }

            // if there's a forum id but not category then derive the category from the forum
            if ((_forumID != 0) && (_categoryID == 0))
            {
                _categoryID = RepositoryRegistry.ForumRepository.GetById(_forumID).CategoryId;
            }
        }

        /// <summary>
        /// Handles the Load event of the BaseForumControl control. This
        /// sets up all the ids for later retrieval based on a QueryString
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void BaseForumControlLoad(object sender, EventArgs e)
        {
            AssignIdsFromQueryStrings();
            DeterminePostMethod();
            ParentLink = ForumApplication.Instance.GetLink(SharePointForumControls.ViewForums);
        }

        /// <summary>
        /// Gets the session for the user (which contains 
        /// details about the user and what they can see).
        /// </summary>
        /// <returns></returns>
        protected UserSession GetSession()
        {
            return UserSession.CreateSession(ForumApplication.Instance.SpUser);
        }

        /// <summary>
        /// Builds the page links.
        /// </summary>
        /// <param name="title">The title.</param>
        /// <param name="url">The link.</param>
        /// <returns></returns>
        //protected PageLinks BuildPageLinks(string title, string url)
        //{
        //    var pageLinks = BuildBasePageLinks();
        //    pageLinks.AddLink(title, url);
        //    return pageLinks;
        //}

        /// <summary>
        /// Adds the box header.
        /// </summary>
        /// <param name="title">The title.</param>
        protected void AddBoxHeader(string title)
        {
            AddBoxHeader(title, true, 1);
        }

        protected void AddBoxHeader(string title, bool closeBox)
        {
            AddBoxHeader(title, closeBox, 1);
        }

        protected void AddBoxHeader(string title, bool closeBox, int colSpan)
        {
            Controls.Add(new LiteralControl("<table width=100% cellspacing=0 cellpadding=3>"));
            Controls.Add(new LiteralControl("<tr>"));
            Controls.Add(new LiteralControl(String.Format("<td colSpan=\"{1}\" class=\"ms-ToolPaneTitle\">{0}</td>", title, colSpan)));
            Controls.Add(new LiteralControl("</tr>"));

            if (closeBox)
            {
                CloseBox();
            }
        }

        protected void CloseBox()
        {
            Controls.Add(new LiteralControl("</table>"));
            Controls.Add(new LiteralControl("<br/>"));
        }

        /// <summary>
        /// Sends server control content to a provided <see cref="T:System.Web.UI.HtmlTextWriter"/> object, which writes the content to
        /// be rendered on
        /// the client.
        /// </summary>
        /// <param name="writer">The <see langword="HtmlTextWriter"/> object that receives the server control content.</param>
        protected override void Render(HtmlTextWriter writer)
        {
            EnsureChildControls();
            //RenderToolBar(writer);
            RenderBody(writer);
            RenderFooter(writer);
        }

        /// <summary>
        /// Renders the footer.
        /// </summary>
        /// <param name="writer">The writer.</param>
        private void RenderFooter(TextWriter writer)
        {
            var footer = new StringBuilder();

            //footer.AppendFormat("<p style=\"text-align:center;font-size:7pt\">");
            //footer.AppendFormat("<br/>");

            _forumTimer.Stop();

            footer.AppendFormat("<!--\r\nThis page was generated in {0:N3} seconds.\r\n-->", _forumTimer.Duration);

            DisplayDebugUserInformation(footer);

            //footer.AppendFormat("</p>");
            writer.Write(footer.ToString());
        }

        /// <summary>
        /// Renders the tool bar.
        /// </summary>
        /// <param name="writer">The writer.</param>
        //private void RenderToolBar(HtmlTextWriter writer)
        //{
        //    _toolBar.Render(writer);
        //}

        /// <summary>
        /// This renders the body of the control by looping through
        /// any child controls in the control array.
        /// </summary>
        /// <param name="writer"></param>
        protected virtual void RenderBody(HtmlTextWriter writer)
        {
            foreach (Control control in Controls)
            {
                control.RenderControl(writer);
            }
        }

        /// <summary>
        /// Creates the button row.
        /// </summary>
        /// <param name="left">The left.</param>
        /// <param name="right">The right.</param>
        /// <returns></returns>
        protected TableRow CreateButtonRow(Button left, Button right)
        {
            var tableRow = new TableRow();

            var tableCell = new TableCell
                                {
                                    ColumnSpan = 2,
                                    Width = Unit.Percentage(100),
                                    HorizontalAlign = HorizontalAlign.Center
                                };

            tableCell.Controls.Add(left);
            tableCell.Controls.Add(new LiteralControl("&nbsp;"));
            tableCell.Controls.Add(right);

            tableRow.Cells.Add(tableCell);

            return tableRow;
        }

        /// <summary>
        /// Redirects to _parent.
        /// </summary>
        protected void RedirectToParent()
        {
            if(ParentLink == null)
                ParentLink = ForumApplication.Instance.GetLink(SharePointForumControls.ViewForums);
            Context.Response.Redirect(ParentLink);
        }

        protected void AddRow(string label, string control)
        {
            Controls.Add(new LiteralControl("<tr>"));
            Controls.Add(new LiteralControl(string.Format("<td align=right class=ms-navframe width=50%><strong>{0}</strong></td>", label)));
            Controls.Add(new LiteralControl(string.Format("<td class=ms-navframe width=50%>{0}</td>", control)));
            Controls.Add(new LiteralControl("</tr>"));
        }

        protected TableRow CreateRow(Control control, string labelName)
        {
            var tableRow = new TableRow();
            var tableCell = new TableCell
                                {
                                    HorizontalAlign = HorizontalAlign.Right,
                                    CssClass = "ms-navframe",
                                    Width = Unit.Percentage(50)
                                };
            tableCell.Controls.Add(new LiteralControl(String.Format("<strong>{0}</strong>", labelName)));
            tableRow.Cells.Add(tableCell);
            tableCell = new TableCell {Width = Unit.Percentage(50)};
            tableCell.Controls.Add(control);
            tableRow.Cells.Add(tableCell);
            return tableRow;
        }

        protected TableRow CreateRow(Control control)
        {
            var tableRow = new TableRow();
            var tableCell = new TableCell
                                {
                                    HorizontalAlign = HorizontalAlign.Center, 
                                    Width = Unit.Percentage(100)
                                };
            tableCell.Controls.Add(control);
            tableRow.Cells.Add(tableCell);
            return tableRow;
        }

        protected void DisplayMessages(MessageCollection messages)
        {
            DisplayMessages(messages, null);
        }

        protected void DisplayMessages(MessageCollection messages, Core.Domain.Entities.Forum forum)
        {
            //foreach (Message post in messages)
            for(var i =  messages.Count - 1; i >=0; i--)
            {
                var post = messages[i];
                Controls.Add(new LiteralControl("<tr>"));

                Controls.Add(new LiteralControl("<td class=\"ms-TPHeader\" width=140px>"));
                Controls.Add(new LiteralControl(string.Format("{0}", HtmlUtility.CreateProfileLink(post.Author))));
                Controls.Add(new LiteralControl("</td>"));

                Controls.Add(new LiteralControl("<td class=\"ms-TPHeader\" width=80%>"));
                Controls.Add(new LiteralControl("<table cellspacing=0 cellpadding=0 width=100%>"));
                Controls.Add(new LiteralControl("<tr>"));
                Controls.Add(new LiteralControl(string.Format("<td><strong>{0}:&nbsp;</strong>{1}</td>", Resources.UI.TextPosted, post.Created)));
                Controls.Add(new LiteralControl(string.Format("<td align=right>")));

                if(forum != null)
                {
                    BuildReplyLinkUI(forum, post);
                    BuildEditLinkUi(forum, post);
                    BuildQuoteLinkUI(forum, post);
                }

                Controls.Add(new LiteralControl(string.Format("</td>")));
                Controls.Add(new LiteralControl("</tr>"));
                Controls.Add(new LiteralControl("</table>"));
                Controls.Add(new LiteralControl("</td>"));

                Controls.Add(new LiteralControl("</tr>"));

                Controls.Add(new LiteralControl("<tr class=\"ms-alternating\">"));
                Controls.Add(new LiteralControl(string.Format("<td valign=\"top\">{0}</td>", FillUserInfoBox(post.Author))));
                Controls.Add(new LiteralControl(string.Format("<td valign=\"top\">{0}</td>", post.Body)));
                Controls.Add(new LiteralControl("</tr>"));

                Controls.Add(new LiteralControl("<tr>"));
                Controls.Add(new LiteralControl("<td colspan=2 class=\"ms-ToolPaneTitle\" style=\"height:5px\"></td>"));
                Controls.Add(new LiteralControl("</tr>"));
            }
        }


        protected void DisplayTopics(TopicCollection topics)
        {
            topics.Sort("LastPost", (Core.Domain.SortDirection)SortDirection.Descending);
            foreach (Topic topic in topics)
            {
                Controls.Add(new LiteralControl("<tr class=\"ms-alternating\">"));
                Controls.Add(new LiteralControl(string.Format("<td valign=\"top\"><img src=\"{0}\"></td>", ForumApplication.Instance.ForumImage)));
                var postLink = ForumApplication.Instance.GetLink(SharePointForumControls.ViewMessages, "topic={0}", topic.Id);
                Controls.Add(new LiteralControl(string.Format("<td align=left><strong><a href=\"{0}\">{1}</a></strong></td>", postLink, topic.Name)));
                Controls.Add(new LiteralControl(string.Format("<td align=middle width=7%>{0}</td>", topic.Replies)));
                Controls.Add(new LiteralControl(string.Format("<td align=middle width=20%>{0}</td>", HtmlUtility.CreateProfileLink(topic.Author))));
                Controls.Add(new LiteralControl(string.Format("<td align=middle width=7%>{0}</td>", topic.Views)));
                Controls.Add(new LiteralControl(string.Format("<td align=middle width=25%>{0}<br>{1}</td>", topic.LastPost.ToString("ddd MMM d, yyyy h:m tt"), topic.Author.Name)));
                Controls.Add(new LiteralControl("</tr>"));
            }
        }
    }
}